import pandas as pd
import numpy as np

# pandas数据映射
"""
-- replace()函数：替换数据
-- map()函数：映射数据,处理某一单独的列，最重要
-- rename()函数：重命名列，替换索引
-- apply()函数：应用函数到数据上，处理整个数据框，既支持Series，也支持DataFrame
-- transform()函数：应用函数到数据上，处理整个数据框，返回一个新的DataFrame
"""

# replace()函数：替换数据
# 使用replace(),对values进行替换操作
print("\n1.replace()函数：替换数据")
index = ['张三', '李四', '王五', '李白']
columns = ['python', 'java', 'web', 'database']
data = np.random.randint(0, 100, size=(4, 4))
df = pd.DataFrame(data, index=index, columns=columns)
print("原始数据：\n", df)
df1 = df.copy()
print("替换前：\n", df1)
print("替换后：\n", df1.replace({5: 50, 10: 100}))  # 将5替换为50，10替换为100

# 2.map()函数：映射数据,处理某一单独的列，最重要
# map（）函数可以使用lambda函数
print("\n2.map()函数：映射数据")
df2 = df.copy()
print("df2数据：\n", df2)

# print("映射前：\n", df2['python'].map({1:10, 2:20, 3:30})) # 由于值是不固定的，所以这只是个例子

# 将python的每个人的成绩乘以10
print("映射后：\n", df2['python'].map(lambda x: x * 10))

# 新增一列
df2['python_score'] = df2['python'].map(lambda x: x * 10)
print("新增一列：\n", df2)

# 新增一列：判断java成绩是否及格
df2['pass_java'] = df2['java'].map(lambda x: '及格' if x >= 60 else '不及格')
print("新增一列：\n", df2)


# 使用普通函数
# 新增一列：判断web成绩是否及格
def wb_pass(x):
    if x < 60:
        return '不及格'
    elif x < 80:
        return '及格'
    else:
        return '优秀'


df2['pass_web'] = df2['web'].map(wb_pass)
print("新增一列：\n", df2)

# 3.rename()函数：重命名列，替换索引
print("\n3.rename()函数：重命名列，替换索引")
df3 = df.copy()
print("df3数据：\n", df3)

print(df3.rename({'张三': "罗峰"}))  # 默认修改行索引名
print(df3.rename({'python': "Python5"}, axis=1))  # 修改列索引名
print(df3.rename(index={"张三": "三月"}))  # 修改行索引名
print(df3.rename(columns={"python": "Python6"}))  # 修改列索引名

# 重置索引
print(df3.reset_index())  # 重置行索引
print(df3.reset_index(drop=True))  # 重置行索引，并删除原来的索引列
# 设置别的列作为索引
print(df3.reset_index())
print(df3.set_index('python'))  # 设置python列作为索引

# 4.apply()函数：应用函数到数据上，处理整个数据框，既支持Series，也支持DataFrame
print("\n4.apply()函数：应用函数到数据上，处理整个数据框，既支持Series，也支持DataFrame")
df4 = df.copy()
print("df4数据：\n", df4)

# 用于处理Series,期中x表达式为Series中元素
print(df4['python'].apply(lambda x: True if x > 50 else False))
print('\n')
# 用于处理DataFrame，期中x表达式为DataFrame中某一行或某一列的Series数据
print(df4.apply(lambda x: x.mean(), axis=0))  # 求每一列数据的平均值
print(df4.apply(lambda x: x.std(), axis=1))  # 求每一行数据的标准差

print('\n')


# 自定义方法
def fn4(x):
    return (np.round(x.mean(), 1), x.count())  # 求每一列数据的平均值和个数


print(df4.apply(fn4, axis=1))

# applymap()函数：应用函数到数据上，处理整个数据框，返回一个新的DataFrame
print("\napplymap()函数：应用函数到数据上，处理整个数据框，返回一个新的DataFrame")
df5 = df.copy()
print("df5数据：\n", df5)

print(df5.map(lambda x: x * 2))  # 所有元素都乘以2

# 5.transform()函数：应用函数到数据上，处理整个数据框，返回一个新的DataFrame
print("\n5.transform()函数：应用函数到数据上，处理整个数据框，返回一个新的DataFrame")
df6 = df.copy()
print("df6数据：\n", df6)
"""
这段代码列出了四个 NumPy 库中的数学函数：
-- np.sqrt: 计算平方根。
-- np.square: 计算平方。
-- np.log: 计算自然对数。
-- np.exp: 计算指数。
"""
# Series中使用transform()函数，可以执行多个函数操作
print(df6['python'].transform([np.sqrt, np.square, np.log, np.exp]))  # 对python列进行四个函数操作


# DataFrame中使用transform()函数，可以执行多个函数操作
def convent(x):
    if x.mean() >= 50:
        return x * 10
    else:
        return x * -10


print(df6.transform(convent))  # 对所有列进行自定义函数操作
print(df6.transform(convent, axis=1))  # 对每一行进行自定义函数操作
